import {
  Component,
  OnInit,
  Directive,
  HostListener,
  Inject
} from "@angular/core";
import { LocaleService, TranslationService, Language } from "angular-l10n";

import createNumberMask from "text-mask-addons/dist/createNumberMask.js";

import big from "@assets/lib/big";
import { IAddOrderRequest } from "@/trade/store/models/trade";

import {
  ISelectSymbolResponse,
  IMu,
  IZi,
  IQuerySymbol,
  IOnSymbol
} from "@/trade/store/models/trade";
import { UserActions } from "@/user/store/actions";
import * as fromUser from "@/user/store/reducers/index";
import * as fromAssets from "@/assets/store/reducers/index";
import * as fromTrade from "@/trade/store/reducers/index";
import * as fromRoot from "@/reducers/index";
import { Store, select } from "@ngrx/store";
import { TradeActions } from "@/trade/store/actions";
import { Subscription, BehaviorSubject } from "rxjs";
import { ActivatedRoute } from "@angular/router";
import { Router, NavigationEnd } from "@angular/router";
import {
  takeUntil,
  mergeMap,
  combineAll,
  debounceTime,
  map,
  filter,
  skip,
  switchMap
} from "rxjs/operators";
import { forkJoin, combineLatest } from "rxjs";
import {
  AsyncValidator,
  NG_ASYNC_VALIDATORS,
  ValidationErrors,
  AbstractControl,
  FormBuilder,
  FormGroup,
  Validators,
  ControlValueAccessor,
  NG_VALUE_ACCESSOR,
  FormControl,
  NgControl
} from "@angular/forms";
import { AssetsActions } from "@/assets/store/actions";

@Component({
  selector: "app-order-sell",
  templateUrl: "./order-sell.component.html",
  styleUrls: ["./order-sell.component.scss"]
})
export class OrderSellComponent implements OnInit {
  @Language() lang: string;

  public pointMask: any;
  public priceMask: any;
  public amountMask: any;

  total: FormControl = new FormControl("0.00000000", {
    validators: [],
    updateOn: "change"
  });

  tv = {
    mu: {
      symbol: "BTC"
    },
    zi: {
      symbol: "ETH"
    }
  };

  avaZi = "0";

  avaMu = "0";

  minAmount = "0";

  minPrice = "0";

  amount1 = "0";

  slider: any = {
    max: 100,
    min: 0,
    step: 1,
    thumbLabel: false,
    val: 0
  };

  req: IAddOrderRequest = {
    price: "",
    uid: "",
    zi: "",
    mu: "",
    type: "sell", // sell
    amount: ""
  };

  point = 8;

  pricePoint = 6;

  amountPoint = 4;

  isLogin$ = this.store.pipe(
    select(fromRoot.userRes),
    filter(e => e.code !== -1),
    map(e => e.code === 200)
  );

  user$ = this.store.pipe(
    select(fromRoot.user),
    filter(user => !!user)
  );

  validateForm: FormGroup;

  assetsMap$ = this.store.pipe(
    select(fromRoot.assetsMap),
    filter(assetsMap => !!assetsMap)
  );

  onSymbol = {
    h: "0.0000",
    l: "0.0000",
    v: "0.0000",
    lastPrice: "0.0000",
    change: "0.00",
    symbol: "",
    sort: 0,
    isLove: false,
    type: "",
    mu: "",
    zi: ""
  };

  querySymbol: IQuerySymbol;

  symbolMap$ = this.store
    .pipe(select(fromRoot.symbolMap))
    .pipe(filter(symbolMap => !!symbolMap));

  sub$ = {
    symbolMapSub$: null,
    assetsMapSub$: null,
    querySub$: null,
    validateFormSub$: null,
    amountSub$: null,
    priceSub$: null,
    userSub$: null,
    addOrderSuccessSub$: null
  };

  addOrderSuccess$ = this.store.pipe(
    select(fromRoot.addOrderRes),
    filter(e => e.code === 200)
  );

  constructor(
    private store: Store<
      fromTrade.State | fromUser.State | fromAssets.State | fromRoot.State
    >,
    private fb: FormBuilder,
    private activatedRoute: ActivatedRoute,
    @Inject("UtilsService") private utilsService
  ) {}

  ngOnInit() {
    this.initPointMast();
    this.initForm();
    this.addListen();
  }

  initPointMast() {
    this.pointMask = {
      mask: createNumberMask({
        prefix: "",
        suffix: "",
        includeThousandsSeparator: false,
        allowDecimal: true,
        requireDecimal: true,
        decimalLimit: this.point,
        decimalSymbol: "."
      })
    };

    this.priceMask = {
      mask: createNumberMask({
        prefix: "",
        suffix: "",
        includeThousandsSeparator: false,
        allowDecimal: true,
        requireDecimal: true,
        decimalLimit: this.pricePoint,
        decimalSymbol: "."
      })
    };

    this.amountMask = {
      mask: createNumberMask({
        prefix: "",
        suffix: "",
        includeThousandsSeparator: false,
        allowDecimal: true,
        requireDecimal: true,
        decimalLimit: this.amountPoint,
        decimalSymbol: "."
      })
    };
  }

  initForm() {
    this.validateForm = this.fb.group({
      price: new FormControl(big.toFixed("0", this.pricePoint), {
        validators: [Validators.required],
        updateOn: "change"
      }),
      amount: new FormControl(big.toFixed("0", this.amountPoint), {
        validators: [Validators.required],
        updateOn: "change"
      })
    });
  }

  unmask(v) {
    return String(v).replace(/_/, "0");
  }

  addListen() {
    this.sub$.symbolMapSub$ = combineLatest(
      this.symbolMap$,
      this.activatedRoute.queryParams
    ).subscribe(([symbolMap, query]) => {
      const { symbol } = query;
      this.querySymbol = this.utilsService.splitQuerySymbol(symbol);
      const onSymbol =
        symbolMap[`${this.querySymbol.zi}${this.querySymbol.mu}`];
      if (!!onSymbol) {
        this.onSymbol = onSymbol;
        this.validateForm.controls.price.setValue(
          big.toFixed(this.onSymbol.lastPrice, this.point)
        );
      }
    });

    this.sub$.assetsMapSub$ = combineLatest(
      this.assetsMap$,
      this.activatedRoute.queryParams
    ).subscribe(([assetsMap, query]) => {
      const [zi, mu] = query.symbol.split("_");
      this.avaMu = Number(assetsMap[mu].ava).toFixed(this.point);
      this.avaZi = Number(assetsMap[zi].ava).toFixed(this.point);
    });

    this.sub$.querySub$ = this.activatedRoute.queryParams.subscribe(e => {
      const [zi, mu] = e.symbol.split("_");
      this.req.zi = zi;
      this.req.mu = mu;
    });

    this.sub$.validateFormSub$ = this.validateForm.valueChanges.subscribe(e => {
      this.req.price = e.price;
      this.req.amount = e.amount;
    });

    this.sub$.userSub$ = this.user$.subscribe(e => {
      // this.req.uid = e.id;
    });

    // here should be to reset amount utils addOrderSuccess
    // this.sub$.priceSub$ = this.validateForm.controls.price.valueChanges.subscribe(
    //   e => {
    //     // 重置 amount
    //     this.validateForm.controls.amount.setValue(
    //       big.toFixed("0", this.point)
    //     );
    //   }
    // );

    this.sub$.addOrderSuccessSub$ = this.addOrderSuccess$.subscribe(e => {
      // 重置 amount
      this.validateForm.controls.amount.setValue(big.toFixed("0", this.point));
      this.store.dispatch(new AssetsActions.SelectAssets({ req: {} }));
    });

    this.sub$.amountSub$ = this.validateForm.controls.amount.valueChanges.subscribe(
      e => {
        const snAmount = big.toFixed(e, this.point);
        const snPrice = big.toFixed(
          this.unmask(this.validateForm.controls.price.value),
          this.point
        );

        const snTotal = big.toFixed(
          this.getTotal(snPrice, snAmount),
          this.point
        );

        const snAvaMu = big.toFixed(this.avaZi, this.point);

        const snAmount100 = big.toFixed(this.avaZi, this.point);

        this.slider.max = Number(snAmount100);

        this.slider.step = Number(
          big.toFixed(big.div(snAmount100, "100"), this.point)
        );

        this.slider.val = Number(snAmount);

        if (big.isGt(snAmount, snAmount100)) {
          this.validateForm.controls.amount.setValue(snAmount100);
          return;
        }

        this.total.setValue(snTotal);
      }
    );
  }

  getTotal(price, amount) {
    const snPrice = big.toFixed(this.unmask(price), this.point);
    const snAmount = big.toFixed(this.unmask(amount), this.point);
    const snRet = big.toFixed(big.multi(snPrice, snAmount), this.point);
    return snRet;
  }

  onInputSlider(e) {
    const { value } = e;
    this.validateForm.controls.amount.setValue(big.toFixed(value, this.point));
  }

  onKeyDownPrice() {}

  onInputPrice(e) {}

  onInputAmount(e) {}

  addOrder() {
    this.store.dispatch(
      new TradeActions.AddOrder({
        req: {
          ...this.req
        }
      })
    );
  }
}
